<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Behavior;

use Think\Log;

/**
 * 系统行为扩展：页面Trace显示输出
 */
class ShowPageTraceBehavior {
	protected $tracePageTabs = array (
			'BASE' => '基本',
			'FILE' => '文件',
			'INFO' => '流程',
			'ERR|NOTIC' => '错误',
			'SQL' => 'SQL',
			'DEBUG' => '调试' 
	);
	
	// 行为扩展的执行入口必须是run
	public function run(&$params) {
		if (! IS_AJAX && ! IS_CLI && C ( 'SHOW_PAGE_TRACE' )) {
			echo $this->showTrace ();
		}
	}
	
	/**
	 * 显示页面Trace信息
	 * 
	 * @access private
	 */
	private function showTrace() {
		// 系统默认显示信息
		$files = get_included_files ();
		$info = array ();
		foreach ( $files as $key => $file ) {
			$info [] = $file . ' ( ' . number_format ( filesize ( $file ) / 1024, 2 ) . ' KB )';
		}
		$trace = array ();
		$base = array (
				'请求信息' => date ( 'Y-m-d H:i:s', $_SERVER ['REQUEST_TIME'] ) . ' ' . $_SERVER ['SERVER_PROTOCOL'] . ' ' . $_SERVER ['REQUEST_METHOD'] . ' : ' . __SELF__,
				'运行时间' => $this->showTime (),
				'吞吐率' => number_format ( 1 / G ( 'beginTime', 'viewEndTime' ), 2 ) . 'req/s',
				'内存开销' => MEMORY_LIMIT_ON ? number_format ( (memory_get_usage () - $GLOBALS ['_startUseMems']) / 1024, 2 ) . ' kb' : '不支持',
				'查询信息' => N ( 'db_query' ) . ' queries ' . N ( 'db_write' ) . ' writes ',
				'文件加载' => count ( get_included_files () ),
				'缓存信息' => N ( 'cache_read' ) . ' gets ' . N ( 'cache_write' ) . ' writes ',
				'配置加载' => count ( C () ),
				'会话信息' => 'SESSION_ID=' . session_id () 
		);
		// 读取应用定义的Trace文件
		$traceFile = COMMON_PATH . 'Conf/trace.php';
		if (is_file ( $traceFile )) {
			$base = array_merge ( $base, include $traceFile );
		}
		$debug = trace ();
		$tabs = C ( 'TRACE_PAGE_TABS', null, $this->tracePageTabs );
		foreach ( $tabs as $name => $title ) {
			switch (strtoupper ( $name )) {
				case 'BASE' : // 基本信息
					$trace [$title] = $base;
					break;
				case 'FILE' : // 文件信息
					$trace [$title] = $info;
					break;
				default : // 调试信息
					$name = strtoupper ( $name );
					if (strpos ( $name, '|' )) { // 多组信息
						$names = explode ( '|', $name );
						$result = array ();
						foreach ( $names as $name ) {
							$result += isset ( $debug [$name] ) ? $debug [$name] : array ();
						}
						$trace [$title] = $result;
					} else {
						$trace [$title] = isset ( $debug [$name] ) ? $debug [$name] : '';
					}
			}
		}
		if ($save = C ( 'PAGE_TRACE_SAVE' )) { // 保存页面Trace日志
			if (is_array ( $save )) { // 选择选项卡保存
				$tabs = C ( 'TRACE_PAGE_TABS', null, $this->tracePageTabs );
				$array = array ();
				foreach ( $save as $tab ) {
					$array [] = $tabs [$tab];
				}
			}
			$content = date ( '[ c ]' ) . ' ' . get_client_ip () . ' ' . $_SERVER ['REQUEST_URI'] . "\r\n";
			foreach ( $trace as $key => $val ) {
				if (! isset ( $array ) || in_array_case ( $key, $array )) {
					$content .= '[ ' . $key . " ]\r\n";
					if (is_array ( $val )) {
						foreach ( $val as $k => $v ) {
							$content .= (! is_numeric ( $k ) ? $k . ':' : '') . print_r ( $v, true ) . "\r\n";
						}
					} else {
						$content .= print_r ( $val, true ) . "\r\n";
					}
					$content .= "\r\n";
				}
			}
			error_log ( str_replace ( '<br/>', "\r\n", $content ), 3, C ( 'LOG_PATH' ) . date ( 'y_m_d' ) . '_trace.log' );
		}
		unset ( $files, $info, $base );
		// 调用Trace页面模板
		ob_start ();
		include C ( 'TMPL_TRACE_FILE' ) ? C ( 'TMPL_TRACE_FILE' ) : THINK_PATH . 'Tpl/page_trace.tpl';
		return ob_get_clean ();
	}
	
	/**
	 * 获取运行时间
	 */
	private function showTime() {
		// 显示运行时间
		G ( 'beginTime', $GLOBALS ['_beginTime'] );
		G ( 'viewEndTime' );
		// 显示详细运行时间
		return G ( 'beginTime', 'viewEndTime' ) . 's ( Load:' . G ( 'beginTime', 'loadTime' ) . 's Init:' . G ( 'loadTime', 'initTime' ) . 's Exec:' . G ( 'initTime', 'viewStartTime' ) . 's Template:' . G ( 'viewStartTime', 'viewEndTime' ) . 's )';
	}
}
